package com.system.demo.service.account.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.system.demo.commonService.MailService;
import com.system.demo.commonService.RedisService;
import com.system.demo.entity.account.NotificationMapper;
import com.system.demo.entity.account.NotificationVO;
import com.system.demo.entity.account.PasswordResetDTO;
import com.system.demo.entity.account.UserInfoVO;
import com.system.demo.entity.database.User;
import com.system.demo.entity.database.UserNotifications;
import com.system.demo.mapper.UserMapper;
import com.system.demo.mapper.UserNotificationsMapper;
import com.system.demo.service.account.AccountService;
import com.system.demo.tool.ResponseResult;
import com.system.demo.utils.JwtUtils;
import com.system.demo.utils.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;


import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.system.demo.service.constant.AccountConstant.AVATAR_PATH;
import static com.system.demo.service.constant.RoleConstant.*;
import static com.system.demo.service.constant.UserNotificationConstant.ALREADY_CHECK;


@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MinioUtils minioUtils;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private MailService mailService;

    @Autowired
    private UserNotificationsMapper userNotificationsMapper;

    @Value("${myIp.ip}")
    private String myIp;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.port}")
    private String port;

    @Value("${app.frontend-url}") // 假设这是前端的根URL
    private String frontendUrl;


    @Override
    public ResponseResult<?> getUserInfo() {
        //获取当前用户的学号
        String uid = StpUtil.getLoginId().toString();
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUid, uid);

        User user = userMapper.selectOne(wrapper);
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setId(userInfoVO.getId());
        userInfoVO.setMail(user.getMail());
        userInfoVO.setUid(uid);
        userInfoVO.setAvatar(user.getAvatar());

        return ResponseResult.success("查询个人信息成功", userInfoVO);
    }

    @Override
    public ResponseResult<?> updateAvatar(MultipartFile avatar) {
        String uid = StpUtil.getLoginId().toString();

        //查找user表中的头像url
        User user = userMapper.selectOne(new QueryWrapper<User>()
                .in("uid", uid));
        if(user == null){
            return ResponseResult.BadRequest("未查找到该用户");
        }
        String oldAvatar = user.getAvatar();
        String avatarPath = uid + "/" + AVATAR_PATH;  //头像保存位置为 2111310216/account
        //  如果与系统默认头像路径不同 则删除之前的头像
        if (!StrUtil.equalsAny(oldAvatar, DEFAULT_BOY_AVATAR, DEFAULT_GIRL_AVATAR, DEFAULT_ADMIN_AVATAR)){
            String objectName = oldAvatar.substring(oldAvatar.lastIndexOf('/') + 1);
            String oldObjectName = avatarPath + "/" +objectName;
            boolean deleteSuccess = minioUtils.deleteFile(bucketName, oldObjectName);if (!deleteSuccess) {
                return ResponseResult.InternalServerError("Minio错误，更换头像失败");
            }
        }
        String originalFilename = avatar.getOriginalFilename();
        //如果与系统默认头像路径相同 则不用删除 直接上传就行
        boolean uploadSuccess = minioUtils.uploadFile(avatar, bucketName, avatarPath, originalFilename);
        if(!uploadSuccess){
            return ResponseResult.InternalServerError("内部服务器错误，请重试");
        }
        String newAvatarPath = "http://" + myIp + ":" + port + "/" + bucketName + "/" + avatarPath + "/" + originalFilename;
        user.setAvatar(newAvatarPath);
        int i = userMapper.updateById(user);
        if(!(i > 0)){
            return ResponseResult.InternalServerError("服务器内部错误，请重试");
        }
        return ResponseResult.success("更换头像成功",newAvatarPath);
    }

    @Override
    public ResponseResult<?> resetPassword(PasswordResetDTO passwordResetDTO) {

        String uid = StpUtil.getLoginId().toString();

        User user = userMapper.selectOne(new QueryWrapper<User>().eq("uid", uid));
        if (user == null) {
            return ResponseResult.BadRequest("用户不存在");
        }

        String encodePassword = DigestUtils.md5DigestAsHex(passwordResetDTO.getOldPassword().getBytes());
        if (!user.getPassword().equals(encodePassword)) {
            return ResponseResult.Unauthorized("原始密码错误");
        }

        String newPassword = passwordResetDTO.getNewPassword();
        // 密码复杂度验证
        if (!isPasswordComplexEnough(newPassword)) {
            return ResponseResult.BadRequest("密码不符合复杂度要求");
        }

        // 对新密码进行加密存储
        String encryptedPassword = DigestUtils.md5DigestAsHex(newPassword.getBytes());
        user.setPassword(encryptedPassword);
        if(user.getLastLoginTime() == null){
            //唯一获取loginTime的地方
            user.setLastLoginTime(LocalDateTime.now());
        }
        // 更新数据库
        if(!(userMapper.updateById(user) > 0)){
            return ResponseResult.InternalServerError("服务器内部错误，请稍后尝试");
        }
        StpUtil.logout();
        return ResponseResult.success("密码修改成功");
    }

    @Override
    public ResponseResult<?> setEmail(String email) {
        // 检查邮箱格式是否正确
        if (!isValidEmail(email)) {
            return ResponseResult.BadRequest("邮箱格式不正确");
        }

        // 没有绑定邮箱的才能绑定，已经有邮箱的用户不允许修改邮箱，只能找管理员reset
        String uid = StpUtil.getLoginId().toString();
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("uid", uid));
        if (user == null) {
            return ResponseResult.NotFound("用户不存在");
        }
        if (user.getMail() != null) {
            return ResponseResult.Unauthorized("请联系系统管理员重置");
        }

        // 如果用户未绑定邮箱，则进行绑定操作
        // 生成包含 uid 和 email 的 JWT Token
        String token = jwtUtils.generateToken(uid, email);

        // 绑定链接（包含 token）
        String bindingLink = frontendUrl + "/verifyEmail?token=" + token;

        //发送邮箱
        mailService.sendBindingMail(email, "设置邮箱", bindingLink);

        return ResponseResult.success("验证邮件发送成功，请前往验证！");
    }

    @Override
    public ResponseResult<?> verifyEmail(String token) {
        try {
            // 解析并验证 token
            JwtUtils.JwtClaims claims = jwtUtils.verifyToken(token);

            String uid = claims.getUid();
            String email = claims.getEmail();

            // 根据 uid 查找用户，并绑定邮箱
            User user = userMapper.selectOne(new QueryWrapper<User>().eq("uid", uid));
            if (user != null) {
                // 绑定邮箱
                user.setMail(email);
                userMapper.updateById(user);
                //jwt只能自己失效，看是否有必须做一个
                return ResponseResult.success("邮箱绑定成功！");
            } else {
                return ResponseResult.NotFound("用户不存在或者链接失效");
            }
        } catch (JWTVerificationException e) {
            return ResponseResult.BadRequest("无效的 token 或 token 已过期");
        }
    }

    @Override
    public ResponseResult<?> getNotifications(Integer page, Integer size) {
        String uid = StpUtil.getLoginId().toString();

        // 分页查询配置
        Page<UserNotifications> pageConfig = new Page<>(page, size);

        // 查询分页数据，按时间倒序排列
        IPage<UserNotifications> pagedNotifications = userNotificationsMapper.selectPage(
                pageConfig,
                new QueryWrapper<UserNotifications>()
                        .eq("uid", uid)
                        .orderByDesc("created_time")
        );

        // 更新通知状态为已读
        List<UserNotifications> notifications = pagedNotifications.getRecords();
        if (!notifications.isEmpty()) {
            List<Integer> notificationIds = notifications.stream()
                    .map(UserNotifications::getId)
                    .collect(Collectors.toList());

            userNotificationsMapper.update(null,
                    new UpdateWrapper<UserNotifications>()
                            .in("id", notificationIds)
                            .set("status", ALREADY_CHECK) // 将 status 更新为 1 表示已读
            );
        }
        List<NotificationVO> notificationVOs = notifications.stream()
                .map(NotificationMapper::mapToNotificationVO)
                .collect(Collectors.toList());


        // 返回分页结果
        Map<String, Object> result = new HashMap<>();
        result.put("total", pagedNotifications.getTotal()); // 通知总数
        result.put("pages", pagedNotifications.getPages()); // 总页数
        result.put("current", pagedNotifications.getCurrent()); // 当前页
        result.put("size", pagedNotifications.getSize()); // 每页大小
        result.put("notifications", notificationVOs); // 通知列表

        return ResponseResult.success("获取最新通知成功", result);
    }



    private boolean isPasswordComplexEnough(String password) {
        // 至少8个字符
        return password.length() >= 8;
        // 包含字母和数字
    }

    private boolean isValidEmail(String email) {
        String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }
}
